<html>
    <head>
        <style>
            body {
                padding: 100px;
                margin: 0;
            }

            #box {
                width: 100px;
                height: 100px;
                background-color: #0077ff;
            }

            [data-layout-correct="false"] {
                background: #dd1144 !important;
                opacity: 1 !important;
            }
        </style>
    </head>
    <body>
        <div id="root"></div>
        <script type="module" src="/src/imports/optimized-appear.js"></script>
        <script type="module" src="/src/imports/script-assert.js"></script>

        <script type="module">
            const {
                motion,
                startOptimizedAppearAnimation,
                optimizedAppearDataAttribute,
                motionValue,
                spring,
            } = window.Motion
            const { matchViewportBox, matchOpacity } = window.Assert
            const root = document.getElementById("root")

            const stiffness = 300
            const damping = 40
            const mass = 1

            // This is the tree to be rendered "server" and client-side.
            const Component = React.createElement(motion.div, {
                id: "box",
                initial: { y: 0, scale: 1 },
                animate: { y: 100, scale: 2 },
                transition: { type: "spring", stiffness, damping, mass },
                /**
                 * On animation start, check the values we expect to see here
                 */
                onAnimationStart: () => {
                    const { top, left } = document
                        .getElementById("box")
                        .getBoundingClientRect()

                    if (top < 110 || top > 140 || left < 60 || left > 90) {
                        showError(box, `unexpected viewport box`)
                    }
                },
                style: { willChange: "opacity" },
                [optimizedAppearDataAttribute]: "a",
            })

            // Emulate server rendering of element
            root.innerHTML = ReactDOMServer.renderToString(Component)

            const springTimeResolution = 10

            function generateSpringKeyframes(from, to) {
                let t = 0
                const keyframes = []
                const springAnimation = spring({
                    keyframes: [from, to],
                    stiffness,
                    damping,
                    mass,
                })
                let state = { done: false, value: from }

                while (!state.done) {
                    state = springAnimation.next(t)
                    keyframes.push(state.value)
                    t += springTimeResolution
                }

                return keyframes
            }

            const yKeyframes = generateSpringKeyframes(0, 100)
            const scaleKeyframes = generateSpringKeyframes(1, 2)
            const maxKeyframes = Math.max(
                yKeyframes.length,
                scaleKeyframes.length
            )

            const transformOptions = {
                duration: maxKeyframes * springTimeResolution,
                ease: "linear",
            }

            const transformKeyframes = []
            for (let i = 0; i < maxKeyframes; i++) {
                transformKeyframes.push(
                    `translateY(${
                        yKeyframes[Math.min(i, yKeyframes.length - 1)]
                    }px) scale(${
                        scaleKeyframes[Math.min(i, scaleKeyframes.length - 1)]
                    })`
                )
            }

            // Start Motion animations
            const animation = startOptimizedAppearAnimation(
                document.getElementById("box"),
                "transform",
                transformKeyframes,
                transformOptions,
                (animation) => {
                    // Hydrate root mid-way through animation
                    setTimeout(() => {
                        ReactDOMClient.hydrateRoot(root, Component)
                    }, 100)
                }
            )
        </script>
    </body>
</html>
